package de.slothsoft.wasbinich.android;

import android.app.AlertDialog;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import com.facebook.AppEventsLogger;
import com.facebook.FacebookAuthorizationException;
import com.facebook.FacebookOperationCanceledException;
import com.facebook.FacebookRequestError;
import com.facebook.Request;
import com.facebook.Response;
import com.facebook.Session;
import com.facebook.SessionState;
import com.facebook.UiLifecycleHelper;
import com.facebook.model.GraphObject;
import com.facebook.model.GraphUser;
import com.facebook.widget.LoginButton;
import com.facebook.widget.ProfilePictureView;

import de.slothsoft.wasbinich.android.util.StyleUtil;

public class FacebookActivity extends AbstractActivity {

    public static final String ARG_MESSAGE = "message"; //$NON-NLS-1$
    private static final String PERMISSION = "publish_actions"; //$NON-NLS-1$
    private static final String PENDING_ACTION_BUNDLE_KEY = "de.slothsoft.wasbinich.android.FacebookActivity:PendingAction"; //$NON-NLS-1$

    private ProfilePictureView profilePictureView;
    private TextView greeting;
    private PendingAction pendingAction = PendingAction.NONE;
    private GraphUser user;

    private enum PendingAction {
	NONE, POST_STATUS_UPDATE
    }

    private UiLifecycleHelper uiHelper;

    private Session.StatusCallback callback = new Session.StatusCallback() {
	@Override
	public void call(Session session, SessionState state, Exception exception) {
	    onSessionStateChange(session, state, exception);
	}
    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	this.uiHelper = new UiLifecycleHelper(this, this.callback);
	this.uiHelper.onCreate(savedInstanceState);

	if (savedInstanceState != null) {
	    String name = savedInstanceState.getString(PENDING_ACTION_BUNDLE_KEY);
	    this.pendingAction = PendingAction.valueOf(name);
	}

	setContentView(R.layout.activity_facebook);
	hookListeners();

	this.profilePictureView = (ProfilePictureView) findViewById(R.id.facebook_profilePicture);
	this.greeting = (TextView) findViewById(R.id.facebook_greeting);
	getMessageText().setText(getIntent().getCharSequenceExtra(ARG_MESSAGE));
    }

    private void hookListeners() {
	LoginButton loginButton = (LoginButton) findViewById(R.id.facebook_loginButton);
	loginButton.setUserInfoChangedCallback(new LoginButton.UserInfoChangedCallback() {
	    @Override
	    public void onUserInfoFetched(GraphUser user) {
		FacebookActivity.this.user = user;
		updateUI();
		// It's possible that we were waiting for this.user to
		// be populated in order to post a
		// status update.
		handlePendingAction();
	    }
	});
	getPostStatusUpdateButton().setOnClickListener(new View.OnClickListener() {
	    @Override
	    public void onClick(View view) {
		onClickPostStatusUpdate();
	    }
	});
	StyleUtil.styleButton(this, getPostStatusUpdateButton());
    }

    @Override
    protected void onResume() {
	super.onResume();
	this.uiHelper.onResume();

	// Call the 'activateApp' method to log an app event for use in
	// analytics and advertising reporting. Do so in
	// the onResume methods of the primary Activities that an app may be
	// launched into.
	AppEventsLogger.activateApp(this);

	updateUI();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
	super.onSaveInstanceState(outState);
	this.uiHelper.onSaveInstanceState(outState);

	outState.putString(PENDING_ACTION_BUNDLE_KEY, this.pendingAction.name());
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
	super.onActivityResult(requestCode, resultCode, data);
	this.uiHelper.onActivityResult(requestCode, resultCode, data, null);
    }

    @Override
    public void onPause() {
	super.onPause();
	this.uiHelper.onPause();
    }

    @Override
    public void onDestroy() {
	super.onDestroy();
	this.uiHelper.onDestroy();
    }

    private void onSessionStateChange(Session session, SessionState state, Exception exception) {
	if (this.pendingAction != PendingAction.NONE
		&& (exception instanceof FacebookOperationCanceledException || exception instanceof FacebookAuthorizationException)) {
	    new AlertDialog.Builder(FacebookActivity.this).setTitle(R.string.facebook_cancelled)
		    .setMessage(R.string.facebook_permission_not_granted).setPositiveButton(R.string.facebook_ok, null)
		    .show();
	    this.pendingAction = PendingAction.NONE;
	} else if (state == SessionState.OPENED_TOKEN_UPDATED) {
	    handlePendingAction();
	}
	updateUI();
    }

    private void updateUI() {
	Session session = Session.getActiveSession();
	boolean enableButtons = session != null && session.isOpened();
	getPostStatusUpdateButton().setEnabled(enableButtons);

	if (enableButtons && this.user != null) {
	    this.profilePictureView.setProfileId(this.user.getId());
	    this.greeting.setText(getString(R.string.facebook_hello_user, this.user.getFirstName()));
	} else {
	    this.profilePictureView.setProfileId(null);
	    this.greeting.setText(null);
	}
    }

    @SuppressWarnings("incomplete-switch")
    private void handlePendingAction() {
	PendingAction previouslyPendingAction = this.pendingAction;
	// These actions may re-set pendingAction if they are still pending, but
	// we assume they
	// will succeed.
	this.pendingAction = PendingAction.NONE;

	switch (previouslyPendingAction) {
	case POST_STATUS_UPDATE:
	    postStatusUpdate();
	    break;
	}
    }

    private interface GraphObjectWithId extends GraphObject {
	String getId();
    }

    private void showPublishResult(String message, GraphObject result, FacebookRequestError error) {
	String title = null;
	String alertMessage = null;
	if (error == null) {
	    title = getString(R.string.facebook_success);
	    String id = result.cast(GraphObjectWithId.class).getId();
	    alertMessage = getString(R.string.facebook_successfully_posted_post, id);
	} else {
	    title = getString(R.string.facebook_error);
	    alertMessage = error.getErrorMessage();
	}

	new AlertDialog.Builder(this).setTitle(title).setMessage(alertMessage)
		.setPositiveButton(R.string.facebook_ok, null).show();
	if (error == null) {
	    finish();
	}
    }

    private void onClickPostStatusUpdate() {
	performPublish(PendingAction.POST_STATUS_UPDATE);
    }

    private void postStatusUpdate() {
	if (this.user != null && hasPublishPermission()) {
	    final CharSequence message = getMessageText().getText();
	    if (message != null) {
		Request request = Request.newStatusUpdateRequest(Session.getActiveSession(), message.toString(), null,
			null, new Request.Callback() {
			    @Override
			    public void onCompleted(Response response) {
				showPublishResult(message.toString(), response.getGraphObject(), response.getError());
			    }
			});
		request.executeAsync();
	    }
	} else {
	    this.pendingAction = PendingAction.POST_STATUS_UPDATE;
	}
    }

    private boolean hasPublishPermission() {
	Session session = Session.getActiveSession();
	return session != null && session.getPermissions().contains(PERMISSION);
    }

    private void performPublish(PendingAction action) {
	Session session = Session.getActiveSession();
	if (session != null) {
	    this.pendingAction = action;
	    if (hasPublishPermission()) {
		// We can do the action right away.
		handlePendingAction();
		return;
	    }
	    if (session.isOpened()) {
		// We need to get new permissions, then complete the action when
		// we get called back.
		session.requestNewPublishPermissions(new Session.NewPermissionsRequest(this, PERMISSION));
		return;
	    }
	}
    }

    protected Button getPostStatusUpdateButton() {
	return (Button) findViewById(R.id.facebook_postStatusUpdateButton);
    }

    protected EditText getMessageText() {
	return (EditText) findViewById(R.id.facebook_message);
    }

}
